<template>
  <div>
    <el-dialog v-model="isShow" draggable width="1500px" @close="close" :destroy-on-close="true">
      <div class="main-box">
        <div class="table-box">
          <ProTable
            ref="proTableRef"
            title="api接口列表"
            :columns="columns"
            :row-key="'apiRoute'"
            :data="apiResourceData"
            @selection-change="selectionChange"
            @page-index-change="handlePageChange"
            @page-size-change="handlePageChange"
            :span-method="objectSpanMethod"
          >
            <template #tableHeader>
              <el-space class="align-container">
                <el-input v-model="searchKey" :placeholder="$t('message.rolePlaceholder.api')" />
                <el-button type="primary" :icon="Search" @click="refresh">
                  {{ $t("message.commonBtn.query") }}
                </el-button>
                <el-button type="info" :icon="Refresh" @click="reset"> {{ $t("message.commonBtn.reset") }} </el-button>
              </el-space>
            </template>
            <template #dataScope="scope">
              <el-space v-if="scope.row.isDataScope">
                <el-radio-group
                  v-model="scope.row.dataScopeType"
                  @change="changeDataScope(scope.row)"
                  :disabled="sysRole.code == 'SysCommon' || isChoiceDataScope(scope.row)"
                >
                  <el-radio v-for="d in props.dataScope" :key="d.value" :value="d.value">{{ d.name }}</el-radio>
                </el-radio-group>
                <el-button
                  v-if="
                    scope.row.dataScopeType === 'DataScopeDefine' || scope.row.dataScopeType === 'DataScopeAppointOrgAndChild'
                  "
                  type="primary"
                  size="default"
                  text
                  @click="choiceOrg(scope.row)"
                  ><el-badge :value="scope.row.defineScopeOrgList?.length" class="item">
                    {{ $t("message.roleInfo.choiceOrg") }}
                  </el-badge>
                </el-button>
              </el-space>
            </template>
          </ProTable>
        </div>
      </div>
      <OrgSelector ref="orgSelectorRef" @return-data="setChoiceOrgIdList" />
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="close" size="default">{{ $t("message.commonBtn.cancel") }}</el-button>
          <el-button type="primary" @click="submit" size="default">{{ $t("message.commonBtn.submit") }}</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup lang="ts" name="GrantApiResource">
import menuApi from "@/api-services/apis/system/menuApi";
import roleApi from "@/api-services/apis/system/roleApi";
import { DictData, SysMenu, SysRole } from "@/api-services/models/system";
import ProTable from "@/components/ProTable/index.vue";
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
import { TableColumnCtx } from "element-plus";
import OrgSelector from "@/components/Selector/orgSelector.vue";
import { feature } from "@/utils/axios-utils";
import { Search, Refresh } from "@element-plus/icons-vue";
import { useOrgStore } from "@/stores/modules/org";
import { useI18n } from "vue-i18n";
import { NotificationError, NotificationSuccess } from "@/utils/notification";
const { t } = useI18n();
const proTableRef = ref<ProTableInstance>();
const orgSelectorRef = ref<InstanceType<typeof OrgSelector> | null>(null);
const sysRole = ref<SysRole.SysRoleInfo>({});
const isShow = ref(false);
const apiResourceData = ref<Array<SysMenu.ApiResource>>([]);
const apiResourceDataAll = ref<Array<SysMenu.ApiResource>>([]);
const selected = ref<Array<SysMenu.ResourceInfo>>([]);
const spanArr = ref<Array<SpanArray>>([]);
const searchKey = ref("");
const orgStore = useOrgStore();
const props = defineProps({
  dataScope: Array<DictData.SysDictData>
});
/** 列合并 */
interface SpanMethodProps {
  // 行
  row: SysMenu.ApiResource;
  // 列
  column: TableColumnCtx<SysMenu.ApiResource>;
  // 行索引
  rowIndex: number;
  // 列索引
  columnIndex: number;
}

interface SpanArray {
  name: string;
  index: number[];
}

const columns: ColumnProps<SysMenu.ApiResource>[] = [
  { prop: "controller", label: t("message.roleInfo.controller"), minWidth: 100 },
  { type: "selection", width: 60 },
  { prop: "resourceName", label: t("message.roleInfo.api"), minWidth: 300, align: "left" },
  { prop: "dataScope", label: t("message.roleInfo.dataScope"), minWidth: 700, align: "left" }
];

const initRoleResource = async () => {
  if (!apiResourceDataAll.value?.length) {
    const resourceRes = await menuApi.getApiResource();
    apiResourceDataAll.value = resourceRes.data.data;
  }
  //查询已分配资源
  const ownResourceRes = await roleApi.getOwnResource({ id: sysRole.value.id! });
  const ownResource = ownResourceRes.data.data.resources;
  handelData(apiResourceDataAll.value, ownResource);
};

//处理资源数据
const handelData = (resourceRes: Array<SysMenu.ApiResource>, ownResource: Array<SysMenu.ResourceInfo>) => {
  apiResourceData.value = JSON.parse(JSON.stringify(resourceRes));
  firstHandlePage();
  if (!ownResource) return;
  setTimeout(() => {
    ownResource?.forEach((ownResource: SysMenu.ResourceInfo) => {
      let index = apiResourceData.value.findIndex((it: SysMenu.ApiResource) => ownResource.apiRoute === it.apiRoute);
      if (index > -1) {
        proTableRef.value?.element?.toggleRowSelection(apiResourceData.value[index], true);
        if (apiResourceData.value[index].isDataScope) {
          apiResourceData.value[index].dataScopeType = ownResource.dataScopeType;
          apiResourceData.value[index].defineScopeOrgList = ownResource.defineScopeOrgList;
        }
      }
    });
  }, 30);
};

const getSpanCell = (data: SysMenu.ApiResource[]) => {
  spanArr.value = [];
  data.forEach((item: SysMenu.ApiResource, index) => {
    if (spanArr.value[item.controller!]) {
      spanArr.value[item.controller!].push(index);
    } else {
      spanArr.value[item.controller!] = [index];
    }
  });
};
/** 列合并*/
const objectSpanMethod = ({ row, rowIndex, columnIndex }: SpanMethodProps) => {
  // 如果列索引为0
  if (columnIndex == 0) {
    // 获取父名称
    const controller = row.controller!;
    // 获取父名称的索引数组
    const indexArr = spanArr.value[controller];
    // 如果行索引等于索引数组的第一个
    if (indexArr && rowIndex === indexArr[0]) {
      return { rowspan: indexArr.length, colspan: 1 };
    } else {
      return { rowspan: 0, colspan: 0 };
    }
  }
};
const firstHandlePage = () => {
  const data = apiResourceData.value.slice(0, 10);
  getSpanCell(data);
};
const handlePageChange = () => {
  const pageSize = proTableRef.value?.pageable.pageSize ?? 1;
  const pageIndex = proTableRef.value?.pageable.pageIndex ?? 10;
  const data = apiResourceData.value.slice((pageIndex - 1) * pageSize, pageIndex * pageSize);
  getSpanCell(data);
};
const selectionChange = (val: Array<SysMenu.ApiResource>) => {
  apiResourceData.value.forEach(item => {
    //如果接口不用设置数据范围，那么不用做后续处理
    if (!item.isDataScope) return;
    let indexCurSelected = val.findIndex(it => it.apiRoute === item.apiRoute);
    //如果没有被选中，且该接口需要设置数据范围，那么就将数据范围信息清除掉
    if (indexCurSelected == -1) {
      item.dataScopeType = "";
      item.defineScopeOrgList = [];
      return;
    }
    //是否在已选中列表中
    let selectIndex = selected.value.findIndex(it => item.apiRoute === it.apiRoute);
    //如果已在，那么不做处理
    if (selectIndex > -1) return;
    //如果不在，则默认数据范围和组织列表为角色所设置的
    item.dataScopeType = sysRole.value.dataScope;
    item.defineScopeOrgList = sysRole.value.defineScopeOrgList;
  });
  selected.value = val;
};

const isChoiceDataScope = (row: SysMenu.ApiResource) => {
  let index = selected.value.findIndex(it => row.apiRoute === it.apiRoute);
  return index === -1;
};
const changeDataScope = (row: SysMenu.ApiResource) => {
  if (!row.isDataScope) return;
  let indexSelected = selected.value.findIndex(item => item.apiRoute === row.apiRoute);
  if (indexSelected > -1) {
    //改变数据范围时，清空组织列表
    selected.value[indexSelected].defineScopeOrgList = [];
    selected.value[indexSelected].dataScopeType = row.dataScopeType;
  }
};

const refresh = () => {
  if (!searchKey.value) {
    apiResourceData.value = apiResourceDataAll.value;
  } else {
    apiResourceData.value = apiResourceDataAll.value.filter(item => {
      return item.resourceName!.indexOf(searchKey.value) > -1 || item.controller!.indexOf(searchKey.value) > -1;
    });
  }
  setTimeout(() => {
    proTableRef.value?.refreshTable();
  }, 30);
  handelData(apiResourceData.value, selected.value);
};
const reset = () => {
  searchKey.value = "";
  refresh();
};
const currentRow = ref<SysMenu.ApiResource>({});
const choiceOrg = async (row: SysMenu.ApiResource) => {
  let orgTree = await orgStore.orgSelectorGet;
  const param = {
    checkStrictly: true,
    defaultValue: row.defineScopeOrgList,
    data: orgTree
  };
  currentRow.value = row;
  orgSelectorRef.value?.orgSelector(param);
};
const setChoiceOrgIdList = (data: number[]) => {
  currentRow.value.defineScopeOrgList = data;
};
const openGrantResource = async (role: SysRole.SysRoleInfo) => {
  sysRole.value = role;
  await initRoleResource();
  isShow.value = true;
};
const close = () => {
  selected.value = [];
  apiResourceData.value = [];
  searchKey.value = "";
  proTableRef.value?.clearTable();
  proTableRef.value?.clearSelectedList();
  isShow.value = false;
};
const submit = async () => {
  // let resourceList: Array<SysMenu.ResourceInfo> = [];
  // selected.value.forEach(item => {
  //   resourceList.push(item);
  // });
  let input = { id: sysRole.value.id!, resources: selected.value };
  const [err] = await feature(roleApi.grantRoleResource(input));
  if (err) {
    NotificationError(err.message);
  } else {
    NotificationSuccess(t("message.roleAlter.grantApiSuccess"));
    close();
  }
};
defineExpose({ openGrantResource });
</script>
<style lang="scss" scoped>
:deep(.main-box) {
  height: 640px;
  max-height: 640px !important;
  :deep(.el-scrollbar__bar.is-vertical) {
    display: block !important;
  }
}
:deep(.el-scrollbar__bar.is-horizontal) {
  display: block !important;
}

// :deep(.el-scrollbar__bar.is-vertical) {
//   display: block !important;
// }
.align-container {
  display: flex;
  align-items: center; /* 垂直居中 */
}
</style>
